//#include "stdafx.h"
#include "TimeVal.h"
#include "PKToonDef.h"

namespace catan
{
	const long ONE_SEC_IN_USEC = 1000000L;

	TimeVal::TimeVal()
	{
		tv_sec = tv_usec = 0;
	}

	TimeVal::TimeVal(const TimeVal& other)
	{
		tv_sec = other.tv_sec;
		tv_usec = other.tv_usec;
	}

	const TimeVal& TimeVal::Now()
	{
		static TimeVal tv;
#ifdef WIN32
		FILETIME ftime;
		GetSystemTimeAsFileTime(&ftime);
		const INT64 skew = 0x19db1ded53e8000i64;
		ULARGE_INTEGER _100ns;
		_100ns.LowPart = ftime.dwLowDateTime;
		_100ns.HighPart = ftime.dwHighDateTime;
		_100ns.QuadPart -= skew;

		// Convert 100ns units to seconds;
		tv.tv_sec = (long) (_100ns.QuadPart / (10 * 1000 * 1000));
		// Convert remainder to nanoseconds;
		tv.tv_usec = (long) ((_100ns.QuadPart % (10 * 1000 * 1000)) / 10);

		tv.Normalize();
#else
		gettimeofday(&tv, 0);
#endif
		return tv;
	}

	double TimeVal::ToSeconds() const
	{
		return tv_sec + (double)tv_usec / ONE_SEC_IN_USEC;
	}

	long long TimeVal::ToMilliseconds() const
	{
#ifdef WIN32
		return tv_sec * 1000i64 + tv_usec / 1000i64;
#else
		return tv_sec * 1000LL + tv_usec / 1000LL;
#endif
	}

	void TimeVal::Reload()
	{
		(*this) = TimeVal::Now();
	}

	bool TimeVal::operator < (const TimeVal& other) const
	{
		if (tv_sec < other.tv_sec)
		{
			return true;
		}
		else if (tv_sec == other.tv_sec)
		{
			return tv_usec < other.tv_usec;
		}
		else
		{
			return false;
		}
	}

	bool TimeVal::operator == (const TimeVal& other) const
	{
		return tv_sec == other.tv_sec && tv_usec == other.tv_usec;
	}

	bool TimeVal::operator != (const TimeVal& other) const
	{
		return !(*this == other);
	}

	bool TimeVal::operator > (const TimeVal& other) const
	{
		return !(*this < other || *this == other);
	}

	bool TimeVal::operator <= (const TimeVal& other) const
	{
		return *this < other || *this == other;
	}

	bool TimeVal::operator >= (const TimeVal& other) const
	{
		return *this > other || *this == other;
	}

	TimeVal& TimeVal::operator = (const TimeVal& other)
	{
		if (&other == this)
		{
			return *this;
		}
		tv_sec = other.tv_sec;
		tv_usec = other.tv_usec;
		return *this;
	}

	TimeVal TimeVal::operator - (const TimeVal& other) const
	{
		TimeVal ret;
		ret.tv_sec = tv_sec - other.tv_sec;
		ret.tv_usec = tv_usec - other.tv_usec;
		ret.Normalize();
		return ret;
	}

	TimeVal TimeVal::operator + (const TimeVal& other) const
	{
		TimeVal ret;
		ret.tv_sec = tv_sec + other.tv_sec;
		ret.tv_usec = tv_usec + other.tv_usec;
		ret.Normalize();
		return ret;
	}

	TimeVal& TimeVal::operator -= (const TimeVal& other)
	{
		tv_sec -= other.tv_sec;
		tv_usec -= other.tv_usec;
		this->Normalize();
		return *this;
	}

	TimeVal& TimeVal::operator += (const TimeVal& other)
	{
		tv_sec += other.tv_sec;
		tv_usec += other.tv_usec;
		this->Normalize();
		return *this;
	}

	inline void TimeVal::Normalize()
	{
		if (tv_usec >= ONE_SEC_IN_USEC)
		{
			do
			{
				++tv_sec;
				tv_usec -= ONE_SEC_IN_USEC;
			}
			while (tv_usec >= ONE_SEC_IN_USEC);
		}
		else if (tv_usec <= -ONE_SEC_IN_USEC)
		{
			do
			{
				--tv_sec;
				tv_usec += ONE_SEC_IN_USEC;
			}
			while (tv_usec <= -ONE_SEC_IN_USEC);
		}

		if (tv_sec >= 1 && tv_usec < 0)
		{
			--tv_sec;
			tv_usec += ONE_SEC_IN_USEC;
		}
	}
}
